﻿using Athena.Message;
using Athena.Transport;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;

namespace Athena.Runtime.Server.Implementations
{
    using ExceptionHandler;
    public class ServiceExecutor : IServiceExecutor
    {
        private readonly IServiceEntrySelector _serviceEntrySelector;
        private readonly ILogger _logger;
        public ServiceExecutor(IServiceEntrySelector serviceEntrySelector, ILogger<ServiceExecutor> logger)
        {
            _serviceEntrySelector = serviceEntrySelector;
            _logger = logger;
        }

        public async Task ExecuteAsync(ITransportMessageSender transportMessageSender, RpcTransportMessage rpcTransportMessage)
        {
            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation("接收到消息。");
            }

            if (!rpcTransportMessage.IsInvokeMessage)
            {
                return;
            }

            RpcInvokeMessage rpcInvokeMessage;
            try
            {
                rpcInvokeMessage = rpcTransportMessage.GetContent<RpcInvokeMessage>();
            }
            catch (Exception exception)
            {
                _logger.LogError("将接收到的消息反序列化成 TransportMessage<RemoteInvokeMessage> 时发送了错误。", exception);
                return;
            }
            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation("开始执行Service逻辑。");
            }
            var serivceEntry = _serviceEntrySelector.Select(rpcInvokeMessage);
            var rpcInvokeResultMessage = new RpcInvokeResultMessage()
            {
                CorrelationId = rpcInvokeMessage.CorrelationId
            };
            if (serivceEntry == null)
            {
                var rpcException = new RpcException(AthenaRpcInvokeResultCodeDisplay.RpcServiceEntrySelectException, $"获取ServiceEntry失败,Service：{rpcInvokeMessage.CorrelationId} 不存在。");
                rpcInvokeResultMessage.Code = rpcException.Code;
                rpcInvokeResultMessage.Message = rpcException.Message;
            }
            else
            {
                await ExecuteServiceEntryAsync(serivceEntry, rpcInvokeMessage, rpcInvokeResultMessage);
            }

            await SendInvokeResultMessage(transportMessageSender, rpcInvokeResultMessage, rpcTransportMessage.Id);
        }

        private async Task ExecuteServiceEntryAsync(ServiceEntry serviceEntry, RpcInvokeMessage rpcInvokeMessage, RpcInvokeResultMessage rpcInvokeResultMessage)
        {
            try
            {
                var result = await serviceEntry.FuncByExecutor(rpcInvokeMessage.Arguments);

                var task = result as Task;

                if (task == null)
                {
                    rpcInvokeResultMessage.Result = result;
                }
                else
                {
                    task.Wait();
                    var taskType = task.GetType();
                    if (taskType.IsGenericType)
                    {
                        //TODO 待优化
                        rpcInvokeResultMessage.Result = taskType.GetProperty("Result").GetValue(task);
                    }
                    rpcInvokeResultMessage.Code = (int)AthenaRpcInvokeResultCodeDisplay.成功;
                }
            }
            catch (Exception exception)
            {
                if (_logger.IsEnabled(LogLevel.Error))
                    _logger.LogError(exception, "执行Service逻辑时候发生了错误。");
                rpcInvokeResultMessage.Message = GetExceptionMessage(exception);
                rpcInvokeResultMessage.Code = (int)AthenaRpcInvokeResultCodeDisplay.RpcException;
            }
        }

        private async Task SendInvokeResultMessage(ITransportMessageSender transportMessageSender, RpcInvokeResultMessage rpcInvokeResultMessage, string transportMessageId)
        {
            try
            {
                if (_logger.IsEnabled(LogLevel.Debug))
                {
                    _logger.LogDebug("准备发送响应消息。");
                }
                await transportMessageSender.SendAndFlushAsync(RpcTransportMessage.CreateRpcInvokeResultMessage(transportMessageId, rpcInvokeResultMessage));
                if (_logger.IsEnabled(LogLevel.Debug))
                {
                    _logger.LogDebug("响应消息发送成功。");
                }
            }
            catch (Exception exception)
            {
                if (_logger.IsEnabled(LogLevel.Error))
                {
                    _logger.LogError(exception, "发送响应消息时候发生了异常。");
                }
            }
        }

        private static string GetExceptionMessage(Exception exception)
        {
            if (exception == null)
                return string.Empty;

            var message = exception.Message;
            if (exception.InnerException != null)
            {
                message += "|InnerException:" + GetExceptionMessage(exception.InnerException);
            }
            return message;
        }
    }
}
